{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "authorship_tag": "ABX9TyNczSLtaIeZJPFolwCjTueW",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/sugarforever/LangChain-Tutorials/blob/main/LangChain_Expression_Language.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# LangChain的新特性 - Expression Language\n",
        "\n",
        "`LangChain Expression Language` 是一种以声明式方法，轻松地将链或组件组合在一起的机制。通过利用管道操作符，构建的任何链将自动具有完整的同步、异步和流式支持。"
      ],
      "metadata": {
        "id": "OHpaChk4b5UN"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Python管道 - Pipe\n",
        "\n",
        "`Python` 的 `Pipe` 提供了管道实现。请参考 [https://github.com/JulienPalard/Pipe](https://github.com/JulienPalard/Pipe)。 来看几个例子"
      ],
      "metadata": {
        "id": "IAzbVA50cVt1"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### 安装"
      ],
      "metadata": {
        "id": "BL8UBSkOkAVC"
      }
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "pzj4WvdHbeRn",
        "outputId": "8ccdd25b-9056-4002-9f70-daf8d3d8d8fa"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Requirement already satisfied: pipe in /usr/local/lib/python3.10/dist-packages (2.0)\n"
          ]
        }
      ],
      "source": [
        "!pip install -U pipe"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### 最简单一个例子"
      ],
      "metadata": {
        "id": "-cVz9DNDkEYr"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from pipe import select, where\n",
        "\n",
        "numbers = [1, 2, 3, 4, 5]\n",
        "result = list(numbers | where(lambda x: x % 2 == 0) | select(lambda x: x * 2))\n",
        "\n",
        "result"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-9a39Tepgy58",
        "outputId": "7119d313-7b21-42d4-ea61-866737ce02b0"
      },
      "execution_count": 7,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "[4, 8]"
            ]
          },
          "metadata": {},
          "execution_count": 7
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### 小小进阶\n",
        "\n",
        "自定义管道 `uppercase` - 接受一个 `iterable` 参数"
      ],
      "metadata": {
        "id": "X6hYiTkYkJ-L"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from pipe import Pipe\n",
        "\n",
        "uppercase = Pipe(lambda iterable: (x.upper() for x in iterable))\n",
        "\n",
        "words = ['red', 'green', 'blue', 'YELLOW']\n",
        "\n",
        "uppercase_words = list(words | uppercase)\n",
        "\n",
        "uppercase_words"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "rwhNhNzSkOHC",
        "outputId": "6a69c76c-ac24-49bc-e06f-cfb8c7d659d8"
      },
      "execution_count": 26,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "['RED', 'GREEN', 'BLUE', 'YELLOW']"
            ]
          },
          "metadata": {},
          "execution_count": 26
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## LangChain Expression Language与管道\n",
        "\n",
        "`LEL` 通过管道定义操作序列，帮助程序员以更加优雅简洁的编码方式构建功能逻辑。我们来看看如何通过表达式来重构几个经典的LangChain实例。"
      ],
      "metadata": {
        "id": "3c8vpUz3lSEt"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### 安装\n",
        "\n",
        "我们需要安装最新版本的 `langchain` 以确保具有 `LEL` 功能的支持。"
      ],
      "metadata": {
        "id": "bcAYqmcAmLiY"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install -q -U langchain openai"
      ],
      "metadata": {
        "id": "QKFeM3t0mbQQ"
      },
      "execution_count": 23,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "### 提示词模版与模型\n"
      ],
      "metadata": {
        "id": "dIiNbIYimmSa"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import os\n",
        "\n",
        "os.environ['OPENAI_API_KEY'] = '您的有效openai api key'"
      ],
      "metadata": {
        "id": "xCEJ_9XEs6jA"
      },
      "execution_count": 24,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### 提示词模板与模型的传统用法"
      ],
      "metadata": {
        "id": "ivCfgUk5rFn6"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from langchain.prompts import (\n",
        "    ChatPromptTemplate,\n",
        "    HumanMessagePromptTemplate,\n",
        ")\n",
        "from langchain.schema import (\n",
        "    HumanMessage\n",
        ")\n",
        "from langchain.chains import LLMChain\n",
        "\n",
        "human_template=\"Show me the HEX code of color {color_name}\"\n",
        "human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)\n",
        "\n",
        "chat_prompt = ChatPromptTemplate.from_messages([human_message_prompt])\n",
        "chain = LLMChain(llm=ChatOpenAI(), prompt=chat_prompt)\n",
        "\n",
        "chain.run(\"RED\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 36
        },
        "id": "liG2Oc3ZrHWw",
        "outputId": "98b2fbb4-de33-4cbc-b1a7-4427af5f704a"
      },
      "execution_count": 27,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "'The HEX code for the color red is #FF0000.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 27
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### 通过 `LEL` 连接提示词模板与模型"
      ],
      "metadata": {
        "id": "skH8OpgIrKP7"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from langchain.prompts import ChatPromptTemplate\n",
        "from langchain.chat_models import ChatOpenAI\n",
        "\n",
        "model = ChatOpenAI()\n",
        "prompt = ChatPromptTemplate.from_template(\"Show me the HEX code of color {color_name}\")\n",
        "\n",
        "chain = prompt | model\n",
        "\n",
        "chain.invoke({\"color_name\": \"RED\"})"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Ml1opV6bmq9z",
        "outputId": "b05b45af-5f6f-4f9a-f6ec-c1f40e9cee46"
      },
      "execution_count": 34,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "AIMessage(content='The HEX code for the color red is #FF0000.', additional_kwargs={}, example=False)"
            ]
          },
          "metadata": {},
          "execution_count": 34
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### 一个稍稍复杂的例子\n",
        "\n",
        "现在我们给刚才搭建的管道追加一些环节"
      ],
      "metadata": {
        "id": "XuKN7l61uTRO"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### 添加标准输出解析"
      ],
      "metadata": {
        "id": "TBJtYNrMwk8k"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from langchain.schema.output_parser import StrOutputParser\n",
        "\n",
        "chain = prompt | model | StrOutputParser()\n",
        "\n",
        "chain.invoke({\"color_name\": \"RED\"})"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 36
        },
        "id": "eEDRWAYxuaIj",
        "outputId": "814a655d-6aca-44f2-ca96-3b7e48882e33"
      },
      "execution_count": 35,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "'The HEX code of the color red is #FF0000.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 35
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### 添加函数调用\n",
        "\n",
        "我们来给管道中的模型添加一些函数调用。注，我们并不真正调用函数，只解析出函数调用的数据。\n",
        "\n",
        "`JsonOutputFunctionsParser` 用来将函数调用的回复解析为JSON格式，请参考[API 文档](https://api.python.langchain.com/en/latest/output_parsers/langchain.output_parsers.openai_functions.JsonKeyOutputFunctionsParser.html)"
      ],
      "metadata": {
        "id": "y2YheMkRxGrg"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser\n",
        "\n",
        "functions = [\n",
        "    {\n",
        "      \"name\": \"save_color_code\",\n",
        "      \"description\": \"Save the HEX code of color and its name\",\n",
        "      \"parameters\": {\n",
        "        \"type\": \"object\",\n",
        "        \"properties\": {\n",
        "          \"hex_code\": {\n",
        "            \"type\": \"string\",\n",
        "            \"description\": \"The HEX code of the color\"\n",
        "          },\n",
        "          \"color\": {\n",
        "            \"type\": \"string\",\n",
        "            \"description\": \"The color name\"\n",
        "          }\n",
        "        },\n",
        "        \"required\": [\"hex_code\", \"color\"]\n",
        "      }\n",
        "    }\n",
        "  ]\n",
        "chain = prompt | model.bind(function_call = {\"name\": \"save_color_code\"}, functions = functions) | JsonOutputFunctionsParser()\n",
        "\n",
        "chain.invoke({\"color_name\": \"RED\"})"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "obpu_uLAyGS5",
        "outputId": "c8c45e4f-c159-4fe3-fd00-9d21b3b55f46"
      },
      "execution_count": 36,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'hex_code': '#FF0000', 'color': 'RED'}"
            ]
          },
          "metadata": {},
          "execution_count": 36
        }
      ]
    }
  ]
}